/*-------------------------------------------------------------------------
 *
 * int.c
 *	  用于内置整数类型（除了 int8）的函数。
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *	  src/backend/utils/adt/int.c
 *
 *-------------------------------------------------------------------------
 */
/* 
 * 旧评论
 *		I/O例程：
 *		 int2in, int2out, int2recv, int2send
 *		 int4in, int4out, int4recv, int4send
 *		 int2vectorin, int2vectorout, int2vectorrecv, int2vectorsend
 *		布尔运算符：
 *		 inteq, intne, intlt, intle, intgt, intge
 *		算术运算符：
 *		 intpl, intmi, int4mul, intdiv
 *
 *		算术运算符：
 *		 intmod
 */
#include "postgres.h"

#include <ctype.h>
#include <limits.h>
#include <math.h>

#include "catalog/pg_type.h"
#include "common/int.h"
#include "funcapi.h"
#include "libpq/pqformat.h"
#include "nodes/nodeFuncs.h"
#include "nodes/supportnodes.h"
#include "optimizer/optimizer.h"
#include "utils/array.h"
#include "utils/builtins.h"

#define Int2VectorSize(n)	(offsetof(int2vector, values) + (n) * sizeof(int16))

typedef struct
{
	int32		current;
	int32		finish;
	int32		step;
} generate_series_fctx;


/*****************************************************************************
 *	 用户 I/O 例程														 *
 *****************************************************************************/

/* 
 *		int2in			- 将“num”转换为短整型
 */
Datum int2in(PG_FUNCTION_ARGS)
{
	char	   *fc_num = PG_GETARG_CSTRING(0);

	PG_RETURN_INT16(pg_strtoint16(fc_num));
}

/* 
 *		int2out			- 将短整型转换为“num”
 */
Datum int2out(PG_FUNCTION_ARGS)
{
	int16		fc_arg1 = PG_GETARG_INT16(0);
	char	   *fc_result = (char *) palloc(7);	/* 符号，5位数字，'\0' */

	pg_itoa(fc_arg1, fc_result);
	PG_RETURN_CSTRING(fc_result);
}

/* 
 *		int2recv			- 将外部二进制格式转换为int2
 */
Datum int2recv(PG_FUNCTION_ARGS)
{
	StringInfo	fc_buf = (StringInfo) PG_GETARG_POINTER(0);

	PG_RETURN_INT16((int16) pq_getmsgint(fc_buf, sizeof(int16)));
}

/* 
 *		int2send			- 将int2转换为二进制格式
 */
Datum int2send(PG_FUNCTION_ARGS)
{
	int16		fc_arg1 = PG_GETARG_INT16(0);
	StringInfoData fc_buf;

	pq_begintypsend(&fc_buf);
	pq_sendint16(&fc_buf, fc_arg1);
	PG_RETURN_BYTEA_P(pq_endtypsend(&fc_buf));
}

/* 
 * 构造int2vector给定一个原始的int2数组
 *
 * 如果int2s为空，则调用者必须在之后填充值[]
 */
int2vector *
buildint2vector(const int16 *fc_int2s, int fc_n)
{
	int2vector *fc_result;

	fc_result = (int2vector *) palloc0(Int2VectorSize(fc_n));

	if (fc_n > 0 && fc_int2s)
		memcpy(fc_result->values, fc_int2s, fc_n * sizeof(int16));

	/* 
	 * 附加标准数组头。 出于历史原因，我们将索引
	 * 下边界设置为0而不是1。
	 */
	SET_VARSIZE(fc_result, Int2VectorSize(fc_n));
	fc_result->ndim = 1;
	fc_result->dataoffset = 0;		/* 从不包含null */
	fc_result->elemtype = INT2OID;
	fc_result->dim1 = fc_n;
	fc_result->lbound1 = 0;

	return fc_result;
}

/*
 *		int2vectorin			- 将 "num num ..." 转换为内部形式
 */
Datum int2vectorin(PG_FUNCTION_ARGS)
{
	char	   *fc_intString = PG_GETARG_CSTRING(0);
	int2vector *fc_result;
	int			fc_nalloc;
	int			fc_n;

	fc_nalloc = 32;				/* 任意初始大小猜测 */
	fc_result = (int2vector *) palloc0(Int2VectorSize(fc_nalloc));

	for (fc_n = 0;; fc_n++)
	{
		long		fc_l;
		char	   *fc_endp;

		while (*fc_intString && isspace((unsigned char) *fc_intString))
			fc_intString++;
		if (*fc_intString == '\0')
			break;

		if (fc_n >= fc_nalloc)
		{
			fc_nalloc *= 2;
			fc_result = (int2vector *) repalloc(fc_result, Int2VectorSize(fc_nalloc));
		}

		errno = 0;
		fc_l = strtol(fc_intString, &fc_endp, 10);

		if (fc_intString == fc_endp)
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
					 errmsg("invalid input syntax for type %s: \"%s\"",
							"smallint", fc_intString)));

		if (errno == ERANGE || fc_l < SHRT_MIN || fc_l > SHRT_MAX)
			ereport(ERROR,
					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
					 errmsg("value \"%s\" is out of range for type %s", fc_intString,
							"smallint")));

		if (*fc_endp && *fc_endp != ' ')
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
					 errmsg("invalid input syntax for type %s: \"%s\"",
							"smallint", fc_intString)));

		fc_result->values[fc_n] = fc_l;
		fc_intString = fc_endp;
	}

	SET_VARSIZE(fc_result, Int2VectorSize(fc_n));
	fc_result->ndim = 1;
	fc_result->dataoffset = 0;		/* 从不包含null */
	fc_result->elemtype = INT2OID;
	fc_result->dim1 = fc_n;
	fc_result->lbound1 = 0;

	PG_RETURN_POINTER(fc_result);
}

/*
 *		int2vectorout		- 将内部形式转换为 "num num ..."
 */
Datum int2vectorout(PG_FUNCTION_ARGS)
{
	int2vector *fc_int2Array = (int2vector *) PG_GETARG_POINTER(0);
	int			fc_num,
				fc_nnums = fc_int2Array->dim1;
	char	   *fc_rp;
	char	   *fc_result;

	/* 假设符号，5位数字，' ' */
	fc_rp = fc_result = (char *) palloc(fc_nnums * 7 + 1);
	for (fc_num = 0; fc_num < fc_nnums; fc_num++)
	{
		if (fc_num != 0)
			*fc_rp++ = ' ';
		fc_rp += pg_itoa(fc_int2Array->values[fc_num], fc_rp);
	}
	*fc_rp = '\0';
	PG_RETURN_CSTRING(fc_result);
}

/*
 *		int2vectorrecv			- 将外部二进制格式转换为 int2vector
 */
Datum int2vectorrecv(PG_FUNCTION_ARGS)
{
	LOCAL_FCINFO(fc_locfcinfo, 3);
	StringInfo	fc_buf = (StringInfo) PG_GETARG_POINTER(0);
	int2vector *fc_result;

	/*
	 * 通常应该使用 DirectFunctionCall3 调用 array_recv()，但是
	 * 这不起作用，因为 array_recv 想要使用
	 * fcinfo->flinfo->fn_extra 缓存一些数据。所以我们需要传递自己的 flinfo
	 * 参数。
	 */
	InitFunctionCallInfoData(*fc_locfcinfo, fcinfo->flinfo, 3,
							 InvalidOid, NULL, NULL);

	fc_locfcinfo->args[0].value = PointerGetDatum(fc_buf);
	fc_locfcinfo->args[0].isnull = false;
	fc_locfcinfo->args[1].value = ObjectIdGetDatum(INT2OID);
	fc_locfcinfo->args[1].isnull = false;
	fc_locfcinfo->args[2].value = Int32GetDatum(-1);
	fc_locfcinfo->args[2].isnull = false;

	fc_result = (int2vector *) DatumGetPointer(array_recv(fc_locfcinfo));

	Assert(!fc_locfcinfo->isnull);

	/* 安全检查：int2vector 必须是一维，0 基，且无空值 */
	if (ARR_NDIM(fc_result) != 1 ||
		ARR_HASNULL(fc_result) ||
		ARR_ELEMTYPE(fc_result) != INT2OID ||
		ARR_LBOUND(fc_result)[0] != 0)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
				 errmsg("invalid int2vector data")));

	PG_RETURN_POINTER(fc_result);
}

/*
 *		int2vectorsend			- 将 int2vector 转换为二进制格式
 */
Datum int2vectorsend(PG_FUNCTION_ARGS)
{
	return array_send(fcinfo);
}


/*****************************************************************************
 *	 公共例程														 *
 *****************************************************************************/

/*
 *		int4in			- 将 "num" 转换为 int4
 */
Datum int4in(PG_FUNCTION_ARGS)
{
	char	   *fc_num = PG_GETARG_CSTRING(0);

	PG_RETURN_INT32(pg_strtoint32(fc_num));
}

/*
 *		int4out			- 将 int4 转换为 "num"
 */
Datum int4out(PG_FUNCTION_ARGS)
{
	int32		fc_arg1 = PG_GETARG_INT32(0);
	char	   *fc_result = (char *) palloc(12);	/* 符号，10位数字，'\0' */

	pg_ltoa(fc_arg1, fc_result);
	PG_RETURN_CSTRING(fc_result);
}

/*
 *		int4recv			- 将外部二进制格式转换为 int4
 */
Datum int4recv(PG_FUNCTION_ARGS)
{
	StringInfo	fc_buf = (StringInfo) PG_GETARG_POINTER(0);

	PG_RETURN_INT32((int32) pq_getmsgint(fc_buf, sizeof(int32)));
}

/*
 *		int4send			- 将 int4 转换为二进制格式
 */
Datum int4send(PG_FUNCTION_ARGS)
{
	int32		fc_arg1 = PG_GETARG_INT32(0);
	StringInfoData fc_buf;

	pq_begintypsend(&fc_buf);
	pq_sendint32(&fc_buf, fc_arg1);
	PG_RETURN_BYTEA_P(pq_endtypsend(&fc_buf));
}


/*
 *		===================
 *		转换例程
 *		===================
 */

Datum i2toi4(PG_FUNCTION_ARGS)
{
	int16		fc_arg1 = PG_GETARG_INT16(0);

	PG_RETURN_INT32((int32) fc_arg1);
}

Datum i4toi2(PG_FUNCTION_ARGS)
{
	int32		fc_arg1 = PG_GETARG_INT32(0);

	if (unlikely(fc_arg1 < SHRT_MIN) || unlikely(fc_arg1 > SHRT_MAX))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("smallint out of range")));

	PG_RETURN_INT16((int16) fc_arg1);
}

/* 转换 int4 -> bool */
Datum int4_bool(PG_FUNCTION_ARGS)
{
	if (PG_GETARG_INT32(0) == 0)
		PG_RETURN_BOOL(false);
	else
		PG_RETURN_BOOL(true);
}

/* 转换 bool -> int4 */
Datum bool_int4(PG_FUNCTION_ARGS)
{
	if (PG_GETARG_BOOL(0) == false)
		PG_RETURN_INT32(0);
	else
		PG_RETURN_INT32(1);
}

/*
 *		============================
 *		比较运算符例程
 *		============================
 */

/*
 *		inteq			- 如果 arg1 == arg2 返回 1
 *		intne			- 如果 arg1 != arg2 返回 1
 *		intlt			- 如果 arg1 < arg2 返回 1
 *		intle			- 如果 arg1 <= arg2 返回 1
 *		intgt			- 如果 arg1 > arg2 返回 1
 *		intge			- 如果 arg1 >= arg2 返回 1
 */

Datum int4eq(PG_FUNCTION_ARGS)
{
	int32		fc_arg1 = PG_GETARG_INT32(0);
	int32		fc_arg2 = PG_GETARG_INT32(1);

	PG_RETURN_BOOL(fc_arg1 == fc_arg2);
}

Datum int4ne(PG_FUNCTION_ARGS)
{
	int32		fc_arg1 = PG_GETARG_INT32(0);
	int32		fc_arg2 = PG_GETARG_INT32(1);

	PG_RETURN_BOOL(fc_arg1 != fc_arg2);
}

Datum int4lt(PG_FUNCTION_ARGS)
{
	int32		fc_arg1 = PG_GETARG_INT32(0);
	int32		fc_arg2 = PG_GETARG_INT32(1);

	PG_RETURN_BOOL(fc_arg1 < fc_arg2);
}

Datum int4le(PG_FUNCTION_ARGS)
{
	int32		fc_arg1 = PG_GETARG_INT32(0);
	int32		fc_arg2 = PG_GETARG_INT32(1);

	PG_RETURN_BOOL(fc_arg1 <= fc_arg2);
}

Datum int4gt(PG_FUNCTION_ARGS)
{
	int32		fc_arg1 = PG_GETARG_INT32(0);
	int32		fc_arg2 = PG_GETARG_INT32(1);

	PG_RETURN_BOOL(fc_arg1 > fc_arg2);
}

Datum int4ge(PG_FUNCTION_ARGS)
{
	int32		fc_arg1 = PG_GETARG_INT32(0);
	int32		fc_arg2 = PG_GETARG_INT32(1);

	PG_RETURN_BOOL(fc_arg1 >= fc_arg2);
}

Datum int2eq(PG_FUNCTION_ARGS)
{
	int16		fc_arg1 = PG_GETARG_INT16(0);
	int16		fc_arg2 = PG_GETARG_INT16(1);

	PG_RETURN_BOOL(fc_arg1 == fc_arg2);
}

Datum int2ne(PG_FUNCTION_ARGS)
{
	int16		fc_arg1 = PG_GETARG_INT16(0);
	int16		fc_arg2 = PG_GETARG_INT16(1);

	PG_RETURN_BOOL(fc_arg1 != fc_arg2);
}

Datum int2lt(PG_FUNCTION_ARGS)
{
	int16		fc_arg1 = PG_GETARG_INT16(0);
	int16		fc_arg2 = PG_GETARG_INT16(1);

	PG_RETURN_BOOL(fc_arg1 < fc_arg2);
}

Datum int2le(PG_FUNCTION_ARGS)
{
	int16		fc_arg1 = PG_GETARG_INT16(0);
	int16		fc_arg2 = PG_GETARG_INT16(1);

	PG_RETURN_BOOL(fc_arg1 <= fc_arg2);
}

Datum int2gt(PG_FUNCTION_ARGS)
{
	int16		fc_arg1 = PG_GETARG_INT16(0);
	int16		fc_arg2 = PG_GETARG_INT16(1);

	PG_RETURN_BOOL(fc_arg1 > fc_arg2);
}

Datum int2ge(PG_FUNCTION_ARGS)
{
	int16		fc_arg1 = PG_GETARG_INT16(0);
	int16		fc_arg2 = PG_GETARG_INT16(1);

	PG_RETURN_BOOL(fc_arg1 >= fc_arg2);
}

Datum int24eq(PG_FUNCTION_ARGS)
{
	int16		fc_arg1 = PG_GETARG_INT16(0);
	int32		fc_arg2 = PG_GETARG_INT32(1);

	PG_RETURN_BOOL(fc_arg1 == fc_arg2);
}

Datum int24ne(PG_FUNCTION_ARGS)
{
	int16		fc_arg1 = PG_GETARG_INT16(0);
	int32		fc_arg2 = PG_GETARG_INT32(1);

	PG_RETURN_BOOL(fc_arg1 != fc_arg2);
}

Datum int24lt(PG_FUNCTION_ARGS)
{
	int16		fc_arg1 = PG_GETARG_INT16(0);
	int32		fc_arg2 = PG_GETARG_INT32(1);

	PG_RETURN_BOOL(fc_arg1 < fc_arg2);
}

Datum int24le(PG_FUNCTION_ARGS)
{
	int16		fc_arg1 = PG_GETARG_INT16(0);
	int32		fc_arg2 = PG_GETARG_INT32(1);

	PG_RETURN_BOOL(fc_arg1 <= fc_arg2);
}

Datum int24gt(PG_FUNCTION_ARGS)
{
	int16		fc_arg1 = PG_GETARG_INT16(0);
	int32		fc_arg2 = PG_GETARG_INT32(1);

	PG_RETURN_BOOL(fc_arg1 > fc_arg2);
}

Datum int24ge(PG_FUNCTION_ARGS)
{
	int16		fc_arg1 = PG_GETARG_INT16(0);
	int32		fc_arg2 = PG_GETARG_INT32(1);

	PG_RETURN_BOOL(fc_arg1 >= fc_arg2);
}

Datum int42eq(PG_FUNCTION_ARGS)
{
	int32		fc_arg1 = PG_GETARG_INT32(0);
	int16		fc_arg2 = PG_GETARG_INT16(1);

	PG_RETURN_BOOL(fc_arg1 == fc_arg2);
}

Datum int42ne(PG_FUNCTION_ARGS)
{
	int32		fc_arg1 = PG_GETARG_INT32(0);
	int16		fc_arg2 = PG_GETARG_INT16(1);

	PG_RETURN_BOOL(fc_arg1 != fc_arg2);
}

Datum int42lt(PG_FUNCTION_ARGS)
{
	int32		fc_arg1 = PG_GETARG_INT32(0);
	int16		fc_arg2 = PG_GETARG_INT16(1);

	PG_RETURN_BOOL(fc_arg1 < fc_arg2);
}

Datum int42le(PG_FUNCTION_ARGS)
{
	int32		fc_arg1 = PG_GETARG_INT32(0);
	int16		fc_arg2 = PG_GETARG_INT16(1);

	PG_RETURN_BOOL(fc_arg1 <= fc_arg2);
}

Datum int42gt(PG_FUNCTION_ARGS)
{
	int32		fc_arg1 = PG_GETARG_INT32(0);
	int16		fc_arg2 = PG_GETARG_INT16(1);

	PG_RETURN_BOOL(fc_arg1 > fc_arg2);
}

Datum int42ge(PG_FUNCTION_ARGS)
{
	int32		fc_arg1 = PG_GETARG_INT32(0);
	int16		fc_arg2 = PG_GETARG_INT16(1);

	PG_RETURN_BOOL(fc_arg1 >= fc_arg2);
}


/*----------------------------------------------------------
 *	int4 和 int2 的 in_range 函数，
 *	包括跨数据类型的比较。
 *
 *	注意：出于性能原因，我们提供单独的 intN_int8 函数。
 *	这也强制提供 intN_int2，否则带有小整型偏移值的情况将无法解析
 *	使用哪个函数。但这是一种不太可能的情况，因此不要为此重复代码。
 *---------------------------------------------------------*/

Datum in_range_int4_int4(PG_FUNCTION_ARGS)
{
	int32		fc_val = PG_GETARG_INT32(0);
	int32		fc_base = PG_GETARG_INT32(1);
	int32		fc_offset = PG_GETARG_INT32(2);
	bool		fc_sub = PG_GETARG_BOOL(3);
	bool		fc_less = PG_GETARG_BOOL(4);
	int32		fc_sum;

	if (fc_offset < 0)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
				 errmsg("invalid preceding or following size in window function")));

	if (fc_sub)
		fc_offset = -fc_offset;		/* 不能溢出 */

	if (unlikely(pg_add_s32_overflow(fc_base, fc_offset, &fc_sum)))
	{
		/*
		 * 如果 sub 为 false，真实的和肯定大于 val，因此正确
		 * 的答案与 "less" 相同。如果 sub 为 true，真实的和
		 * 肯定小于 val，因此答案为 "!less"。
		 */
		PG_RETURN_BOOL(fc_sub ? !fc_less : fc_less);
	}

	if (fc_less)
		PG_RETURN_BOOL(fc_val <= fc_sum);
	else
		PG_RETURN_BOOL(fc_val >= fc_sum);
}

Datum in_range_int4_int2(PG_FUNCTION_ARGS)
{
	/* 似乎不值得重复代码，因此只需调用 int4_int4 */
	return DirectFunctionCall5(in_range_int4_int4,
							   PG_GETARG_DATUM(0),
							   PG_GETARG_DATUM(1),
							   Int32GetDatum((int32) PG_GETARG_INT16(2)),
							   PG_GETARG_DATUM(3),
							   PG_GETARG_DATUM(4));
}

Datum in_range_int4_int8(PG_FUNCTION_ARGS)
{
	/* 我们必须在 int64 中进行所有数学运算 */
	int64		fc_val = (int64) PG_GETARG_INT32(0);
	int64		fc_base = (int64) PG_GETARG_INT32(1);
	int64		fc_offset = PG_GETARG_INT64(2);
	bool		fc_sub = PG_GETARG_BOOL(3);
	bool		fc_less = PG_GETARG_BOOL(4);
	int64		fc_sum;

	if (fc_offset < 0)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
				 errmsg("invalid preceding or following size in window function")));

	if (fc_sub)
		fc_offset = -fc_offset;		/* 不能溢出 */

	if (unlikely(pg_add_s64_overflow(fc_base, fc_offset, &fc_sum)))
	{
		/*
		 * 如果 sub 为 false，真实的和肯定大于 val，因此正确
		 * 的答案与 "less" 相同。如果 sub 为 true，真实的和
		 * 肯定小于 val，因此答案为 "!less"。
		 */
		PG_RETURN_BOOL(fc_sub ? !fc_less : fc_less);
	}

	if (fc_less)
		PG_RETURN_BOOL(fc_val <= fc_sum);
	else
		PG_RETURN_BOOL(fc_val >= fc_sum);
}

Datum in_range_int2_int4(PG_FUNCTION_ARGS)
{
	/* 我们必须在 int32 中进行所有数学运算 */
	int32		fc_val = (int32) PG_GETARG_INT16(0);
	int32		fc_base = (int32) PG_GETARG_INT16(1);
	int32		fc_offset = PG_GETARG_INT32(2);
	bool		fc_sub = PG_GETARG_BOOL(3);
	bool		fc_less = PG_GETARG_BOOL(4);
	int32		fc_sum;

	if (fc_offset < 0)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
				 errmsg("invalid preceding or following size in window function")));

	if (fc_sub)
		fc_offset = -fc_offset;		/* 不能溢出 */

	if (unlikely(pg_add_s32_overflow(fc_base, fc_offset, &fc_sum)))
	{
		/*
		 * 如果 sub 为 false，真实的和肯定大于 val，因此正确
		 * 的答案与 "less" 相同。如果 sub 为 true，真实的和
		 * 肯定小于 val，因此答案为 "!less"。
		 */
		PG_RETURN_BOOL(fc_sub ? !fc_less : fc_less);
	}

	if (fc_less)
		PG_RETURN_BOOL(fc_val <= fc_sum);
	else
		PG_RETURN_BOOL(fc_val >= fc_sum);
}

Datum in_range_int2_int2(PG_FUNCTION_ARGS)
{
	/* 似乎不值得重复代码，因此只需调用 int2_int4 */
	return DirectFunctionCall5(in_range_int2_int4,
							   PG_GETARG_DATUM(0),
							   PG_GETARG_DATUM(1),
							   Int32GetDatum((int32) PG_GETARG_INT16(2)),
							   PG_GETARG_DATUM(3),
							   PG_GETARG_DATUM(4));
}

Datum in_range_int2_int8(PG_FUNCTION_ARGS)
{
	/* 似乎不值得重复代码，因此只需调用 int4_int8 */
	return DirectFunctionCall5(in_range_int4_int8,
							   Int32GetDatum((int32) PG_GETARG_INT16(0)),
							   Int32GetDatum((int32) PG_GETARG_INT16(1)),
							   PG_GETARG_DATUM(2),
							   PG_GETARG_DATUM(3),
							   PG_GETARG_DATUM(4));
}


/*
 *		int[24]pl		- 返回 arg1 + arg2
 *		int[24]mi		- 返回 arg1 - arg2
 *		int[24]mul		- 返回 arg1 * arg2
 *		int[24]div		- 返回 arg1 / arg2
 */

Datum int4um(PG_FUNCTION_ARGS)
{
	int32		fc_arg = PG_GETARG_INT32(0);

	if (unlikely(fc_arg == PG_INT32_MIN))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("integer out of range")));
	PG_RETURN_INT32(-fc_arg);
}

Datum int4up(PG_FUNCTION_ARGS)
{
	int32		fc_arg = PG_GETARG_INT32(0);

	PG_RETURN_INT32(fc_arg);
}

Datum int4pl(PG_FUNCTION_ARGS)
{
	int32		fc_arg1 = PG_GETARG_INT32(0);
	int32		fc_arg2 = PG_GETARG_INT32(1);
	int32		fc_result;

	if (unlikely(pg_add_s32_overflow(fc_arg1, fc_arg2, &fc_result)))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("integer out of range")));
	PG_RETURN_INT32(fc_result);
}

Datum int4mi(PG_FUNCTION_ARGS)
{
	int32		fc_arg1 = PG_GETARG_INT32(0);
	int32		fc_arg2 = PG_GETARG_INT32(1);
	int32		fc_result;

	if (unlikely(pg_sub_s32_overflow(fc_arg1, fc_arg2, &fc_result)))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("integer out of range")));
	PG_RETURN_INT32(fc_result);
}

Datum int4mul(PG_FUNCTION_ARGS)
{
	int32		fc_arg1 = PG_GETARG_INT32(0);
	int32		fc_arg2 = PG_GETARG_INT32(1);
	int32		fc_result;

	if (unlikely(pg_mul_s32_overflow(fc_arg1, fc_arg2, &fc_result)))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("integer out of range")));
	PG_RETURN_INT32(fc_result);
}

Datum int4div(PG_FUNCTION_ARGS)
{
	int32		fc_arg1 = PG_GETARG_INT32(0);
	int32		fc_arg2 = PG_GETARG_INT32(1);
	int32		fc_result;

	if (fc_arg2 == 0)
	{
		ereport(ERROR,
				(errcode(ERRCODE_DIVISION_BY_ZERO),
				 errmsg("division by zero")));
		/* 确保编译器意识到我们不能到达除法 (gcc bug) */
		PG_RETURN_NULL();
	}

	/*
	 * INT_MIN / -1 是有问题的，因为结果在二进制补码机器上无法表示。
	 * 一些机器产生 INT_MIN，一些产生零，一些抛出异常。
	 * 我们可以通过认识到除以 -1 等同于取反来规避这个问题。
	 */
	if (fc_arg2 == -1)
	{
		if (unlikely(fc_arg1 == PG_INT32_MIN))
			ereport(ERROR,
					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
					 errmsg("integer out of range")));
		fc_result = -fc_arg1;
		PG_RETURN_INT32(fc_result);
	}

	/* 不可能溢出 */

	fc_result = fc_arg1 / fc_arg2;

	PG_RETURN_INT32(fc_result);
}

Datum int4inc(PG_FUNCTION_ARGS)
{
	int32		fc_arg = PG_GETARG_INT32(0);
	int32		fc_result;

	if (unlikely(pg_add_s32_overflow(fc_arg, 1, &fc_result)))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("integer out of range")));

	PG_RETURN_INT32(fc_result);
}

Datum int2um(PG_FUNCTION_ARGS)
{
	int16		fc_arg = PG_GETARG_INT16(0);

	if (unlikely(fc_arg == PG_INT16_MIN))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("smallint out of range")));
	PG_RETURN_INT16(-fc_arg);
}

Datum int2up(PG_FUNCTION_ARGS)
{
	int16		fc_arg = PG_GETARG_INT16(0);

	PG_RETURN_INT16(fc_arg);
}

Datum int2pl(PG_FUNCTION_ARGS)
{
	int16		fc_arg1 = PG_GETARG_INT16(0);
	int16		fc_arg2 = PG_GETARG_INT16(1);
	int16		fc_result;

	if (unlikely(pg_add_s16_overflow(fc_arg1, fc_arg2, &fc_result)))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("smallint out of range")));
	PG_RETURN_INT16(fc_result);
}

Datum int2mi(PG_FUNCTION_ARGS)
{
	int16		fc_arg1 = PG_GETARG_INT16(0);
	int16		fc_arg2 = PG_GETARG_INT16(1);
	int16		fc_result;

	if (unlikely(pg_sub_s16_overflow(fc_arg1, fc_arg2, &fc_result)))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("smallint out of range")));
	PG_RETURN_INT16(fc_result);
}

Datum int2mul(PG_FUNCTION_ARGS)
{
	int16		fc_arg1 = PG_GETARG_INT16(0);
	int16		fc_arg2 = PG_GETARG_INT16(1);
	int16		fc_result;

	if (unlikely(pg_mul_s16_overflow(fc_arg1, fc_arg2, &fc_result)))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("smallint out of range")));

	PG_RETURN_INT16(fc_result);
}

Datum int2div(PG_FUNCTION_ARGS)
{
	int16		fc_arg1 = PG_GETARG_INT16(0);
	int16		fc_arg2 = PG_GETARG_INT16(1);
	int16		fc_result;

	if (fc_arg2 == 0)
	{
		ereport(ERROR,
				(errcode(ERRCODE_DIVISION_BY_ZERO),
				 errmsg("division by zero")));
		/* 确保编译器意识到我们不能到达除法 (gcc bug) */
		PG_RETURN_NULL();
	}

	/*
	 * SHRT_MIN / -1 是有问题的，因为结果在
	 * 二进制补码机器上无法表示。一些机器产生 SHRT_MIN，一些
	 * 产生零，一些抛出异常。我们可以通过认识到除以 -1 等同于取反来规避这个问题。
	 */
	if (fc_arg2 == -1)
	{
		if (unlikely(fc_arg1 == PG_INT16_MIN))
			ereport(ERROR,
					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
					 errmsg("smallint out of range")));
		fc_result = -fc_arg1;
		PG_RETURN_INT16(fc_result);
	}

	/* 不可能溢出 */

	fc_result = fc_arg1 / fc_arg2;

	PG_RETURN_INT16(fc_result);
}

Datum int24pl(PG_FUNCTION_ARGS)
{
	int16		fc_arg1 = PG_GETARG_INT16(0);
	int32		fc_arg2 = PG_GETARG_INT32(1);
	int32		fc_result;

	if (unlikely(pg_add_s32_overflow((int32) fc_arg1, fc_arg2, &fc_result)))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("integer out of range")));
	PG_RETURN_INT32(fc_result);
}

Datum int24mi(PG_FUNCTION_ARGS)
{
	int16		fc_arg1 = PG_GETARG_INT16(0);
	int32		fc_arg2 = PG_GETARG_INT32(1);
	int32		fc_result;

	if (unlikely(pg_sub_s32_overflow((int32) fc_arg1, fc_arg2, &fc_result)))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("integer out of range")));
	PG_RETURN_INT32(fc_result);
}

Datum int24mul(PG_FUNCTION_ARGS)
{
	int16		fc_arg1 = PG_GETARG_INT16(0);
	int32		fc_arg2 = PG_GETARG_INT32(1);
	int32		fc_result;

	if (unlikely(pg_mul_s32_overflow((int32) fc_arg1, fc_arg2, &fc_result)))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("integer out of range")));
	PG_RETURN_INT32(fc_result);
}

Datum int24div(PG_FUNCTION_ARGS)
{
	int16		fc_arg1 = PG_GETARG_INT16(0);
	int32		fc_arg2 = PG_GETARG_INT32(1);

	if (unlikely(fc_arg2 == 0))
	{
		ereport(ERROR,
				(errcode(ERRCODE_DIVISION_BY_ZERO),
				 errmsg("division by zero")));
		/* 确保编译器意识到我们不能到达除法 (gcc bug) */
		PG_RETURN_NULL();
	}

	/* 不可能溢出 */
	PG_RETURN_INT32((int32) fc_arg1 / fc_arg2);
}

Datum int42pl(PG_FUNCTION_ARGS)
{
	int32		fc_arg1 = PG_GETARG_INT32(0);
	int16		fc_arg2 = PG_GETARG_INT16(1);
	int32		fc_result;

	if (unlikely(pg_add_s32_overflow(fc_arg1, (int32) fc_arg2, &fc_result)))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("integer out of range")));
	PG_RETURN_INT32(fc_result);
}

Datum int42mi(PG_FUNCTION_ARGS)
{
	int32		fc_arg1 = PG_GETARG_INT32(0);
	int16		fc_arg2 = PG_GETARG_INT16(1);
	int32		fc_result;

	if (unlikely(pg_sub_s32_overflow(fc_arg1, (int32) fc_arg2, &fc_result)))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("integer out of range")));
	PG_RETURN_INT32(fc_result);
}

Datum int42mul(PG_FUNCTION_ARGS)
{
	int32		fc_arg1 = PG_GETARG_INT32(0);
	int16		fc_arg2 = PG_GETARG_INT16(1);
	int32		fc_result;

	if (unlikely(pg_mul_s32_overflow(fc_arg1, (int32) fc_arg2, &fc_result)))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("integer out of range")));
	PG_RETURN_INT32(fc_result);
}

Datum int42div(PG_FUNCTION_ARGS)
{
	int32		fc_arg1 = PG_GETARG_INT32(0);
	int16		fc_arg2 = PG_GETARG_INT16(1);
	int32		fc_result;

	if (unlikely(fc_arg2 == 0))
	{
		ereport(ERROR,
				(errcode(ERRCODE_DIVISION_BY_ZERO),
				 errmsg("division by zero")));
		/* 确保编译器意识到我们不能到达除法 (gcc bug) */
		PG_RETURN_NULL();
	}

	/*
	 * INT_MIN / -1 是有问题的，因为结果在二进制补码机器上无法表示。
	 * 一些机器产生 INT_MIN，一些产生零，一些抛出异常。
	 * 我们可以通过认识到除以 -1 等同于取反来规避这个问题。
	 */
	if (fc_arg2 == -1)
	{
		if (unlikely(fc_arg1 == PG_INT32_MIN))
			ereport(ERROR,
					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
					 errmsg("integer out of range")));
		fc_result = -fc_arg1;
		PG_RETURN_INT32(fc_result);
	}

	/* 不可能溢出 */

	fc_result = fc_arg1 / fc_arg2;

	PG_RETURN_INT32(fc_result);
}

Datum int4mod(PG_FUNCTION_ARGS)
{
	int32		fc_arg1 = PG_GETARG_INT32(0);
	int32		fc_arg2 = PG_GETARG_INT32(1);

	if (unlikely(fc_arg2 == 0))
	{
		ereport(ERROR,
				(errcode(ERRCODE_DIVISION_BY_ZERO),
				 errmsg("division by zero")));
		/* 确保编译器意识到我们不能到达除法 (gcc bug) */
		PG_RETURN_NULL();
	}

	/*
	 * 一些机器在 INT_MIN % -1 时抛出浮点异常，这有点傻，因为
	 * 正确答案是完全定义好的，即零。
	 */
	if (fc_arg2 == -1)
		PG_RETURN_INT32(0);

	/* 不可能溢出 */

	PG_RETURN_INT32(fc_arg1 % fc_arg2);
}

Datum int2mod(PG_FUNCTION_ARGS)
{
	int16		fc_arg1 = PG_GETARG_INT16(0);
	int16		fc_arg2 = PG_GETARG_INT16(1);

	if (unlikely(fc_arg2 == 0))
	{
		ereport(ERROR,
				(errcode(ERRCODE_DIVISION_BY_ZERO),
				 errmsg("division by zero")));
		/* 确保编译器意识到我们不能到达除法 (gcc bug) */
		PG_RETURN_NULL();
	}

	/*
	 * 一些机器对 INT_MIN % -1 抛出浮点异常，这有点愚蠢，因为正确的答案是完全明确的，即零。(不清楚在处理 int16 时是否会发生这种情况，但我们为了安全起见最好有这个测试。)
	 */
	if (fc_arg2 == -1)
		PG_RETURN_INT16(0);

	/* 不可能溢出 */

	PG_RETURN_INT16(fc_arg1 % fc_arg2);
}


/* int[24]abs()
 * 绝对值
 */
Datum int4abs(PG_FUNCTION_ARGS)
{
	int32		fc_arg1 = PG_GETARG_INT32(0);
	int32		fc_result;

	if (unlikely(fc_arg1 == PG_INT32_MIN))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("integer out of range")));
	fc_result = (fc_arg1 < 0) ? -fc_arg1 : fc_arg1;
	PG_RETURN_INT32(fc_result);
}

Datum int2abs(PG_FUNCTION_ARGS)
{
	int16		fc_arg1 = PG_GETARG_INT16(0);
	int16		fc_result;

	if (unlikely(fc_arg1 == PG_INT16_MIN))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("smallint out of range")));
	fc_result = (fc_arg1 < 0) ? -fc_arg1 : fc_arg1;
	PG_RETURN_INT16(fc_result);
}

/*
 * 最大公约数
 *
 * 返回能够精确整除两个输入的最大正整数。
 * 特殊情况：
 *   - gcd(x, 0) = gcd(0, x) = abs(x)
 *   		因为0可以被任何数字整除
 *   - gcd(0, 0) = 0
 *   		符合前面的定义，并且是一个常见约定
 *
 * 如果任一输入为 INT_MIN，则必须特别小心——gcd(0, INT_MIN)，
 * gcd(INT_MIN, 0) 和 gcd(INT_MIN, INT_MIN) 都等于 abs(INT_MIN)，
 * 而这无法表示为32位有符号整数。
 */
static int32 fc_int4gcd_internal(int32 fc_arg1, int32 fc_arg2)
{
	int32		fc_swap;
	int32		fc_a1,
				fc_a2;

	/*
	 * 将更大的绝对值放入 arg1。
	 *
	 * 在下面的循环中会自动发生这个，但避免了一个
	 * 昂贵的模运算，并简化了下面对 INT_MIN 的特殊情况处理。
	 *
	 * 我们在负空间中执行此操作以处理 INT_MIN。
	 */
	fc_a1 = (fc_arg1 < 0) ? fc_arg1 : -fc_arg1;
	fc_a2 = (fc_arg2 < 0) ? fc_arg2 : -fc_arg2;
	if (fc_a1 > fc_a2)
	{
		fc_swap = fc_arg1;
		fc_arg1 = fc_arg2;
		fc_arg2 = fc_swap;
	}

	/* 处理 INT_MIN 需要特别小心。请参阅上面的注释。 */
	if (fc_arg1 == PG_INT32_MIN)
	{
		if (fc_arg2 == 0 || fc_arg2 == PG_INT32_MIN)
			ereport(ERROR,
					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
					 errmsg("integer out of range")));

		/*
		 * 一些机器对 INT_MIN % -1 抛出浮点异常，
		 * 这有点愚蠢，因为正确的答案是完全
		 * 明确的，即零。防范这种情况并仅返回
		 * 结果，gcd(INT_MIN, -1) = 1。
		 */
		if (fc_arg2 == -1)
			return 1;
	}

	/* 使用欧几里得算法找到 GCD */
	while (fc_arg2 != 0)
	{
		fc_swap = fc_arg2;
		fc_arg2 = fc_arg1 % fc_arg2;
		fc_arg1 = fc_swap;
	}

	/*
	 * 确保结果为正。（我们知道我们不再有 INT_MIN）。
	 */
	if (fc_arg1 < 0)
		fc_arg1 = -fc_arg1;

	return fc_arg1;
}

Datum int4gcd(PG_FUNCTION_ARGS)
{
	int32		fc_arg1 = PG_GETARG_INT32(0);
	int32		fc_arg2 = PG_GETARG_INT32(1);
	int32		fc_result;

	fc_result = fc_int4gcd_internal(fc_arg1, fc_arg2);

	PG_RETURN_INT32(fc_result);
}

/*
 * 最小公倍数
 */
Datum int4lcm(PG_FUNCTION_ARGS)
{
	int32		fc_arg1 = PG_GETARG_INT32(0);
	int32		fc_arg2 = PG_GETARG_INT32(1);
	int32		fc_gcd;
	int32		fc_result;

	/*
	 * 将 lcm(x, 0) = lcm(0, x) = 0 作为特例处理。这可以防止下面在 x 为零时发生的
	 * 除以零错误，以及在 x = INT_MIN 时 GCD 计算中的溢出错误。
	 */
	if (fc_arg1 == 0 || fc_arg2 == 0)
		PG_RETURN_INT32(0);

	/* lcm(x, y) = abs(x / gcd(x, y) * y) */
	fc_gcd = fc_int4gcd_internal(fc_arg1, fc_arg2);
	fc_arg1 = fc_arg1 / fc_gcd;

	if (unlikely(pg_mul_s32_overflow(fc_arg1, fc_arg2, &fc_result)))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("integer out of range")));

	/* 如果结果是 INT_MIN，无法表示。 */
	if (unlikely(fc_result == PG_INT32_MIN))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("integer out of range")));

	if (fc_result < 0)
		fc_result = -fc_result;

	PG_RETURN_INT32(fc_result);
}

Datum int2larger(PG_FUNCTION_ARGS)
{
	int16		fc_arg1 = PG_GETARG_INT16(0);
	int16		fc_arg2 = PG_GETARG_INT16(1);

	PG_RETURN_INT16((fc_arg1 > fc_arg2) ? fc_arg1 : fc_arg2);
}

Datum int2smaller(PG_FUNCTION_ARGS)
{
	int16		fc_arg1 = PG_GETARG_INT16(0);
	int16		fc_arg2 = PG_GETARG_INT16(1);

	PG_RETURN_INT16((fc_arg1 < fc_arg2) ? fc_arg1 : fc_arg2);
}

Datum int4larger(PG_FUNCTION_ARGS)
{
	int32		fc_arg1 = PG_GETARG_INT32(0);
	int32		fc_arg2 = PG_GETARG_INT32(1);

	PG_RETURN_INT32((fc_arg1 > fc_arg2) ? fc_arg1 : fc_arg2);
}

Datum int4smaller(PG_FUNCTION_ARGS)
{
	int32		fc_arg1 = PG_GETARG_INT32(0);
	int32		fc_arg2 = PG_GETARG_INT32(1);

	PG_RETURN_INT32((fc_arg1 < fc_arg2) ? fc_arg1 : fc_arg2);
}

/*
 * 位推动操作符
 *
 *		int[24]and		- 返回 arg1 & arg2
 *		int[24]or		- 返回 arg1 | arg2
 *		int[24]xor		- 返回 arg1 # arg2
 *		int[24]not		- 返回 ~arg1
 *		int[24]shl		- 返回 arg1 << arg2
 *		int[24]shr		- 返回 arg1 >> arg2
 */

Datum int4and(PG_FUNCTION_ARGS)
{
	int32		fc_arg1 = PG_GETARG_INT32(0);
	int32		fc_arg2 = PG_GETARG_INT32(1);

	PG_RETURN_INT32(fc_arg1 & fc_arg2);
}

Datum int4or(PG_FUNCTION_ARGS)
{
	int32		fc_arg1 = PG_GETARG_INT32(0);
	int32		fc_arg2 = PG_GETARG_INT32(1);

	PG_RETURN_INT32(fc_arg1 | fc_arg2);
}

Datum int4xor(PG_FUNCTION_ARGS)
{
	int32		fc_arg1 = PG_GETARG_INT32(0);
	int32		fc_arg2 = PG_GETARG_INT32(1);

	PG_RETURN_INT32(fc_arg1 ^ fc_arg2);
}

Datum int4shl(PG_FUNCTION_ARGS)
{
	int32		fc_arg1 = PG_GETARG_INT32(0);
	int32		fc_arg2 = PG_GETARG_INT32(1);

	PG_RETURN_INT32(fc_arg1 << fc_arg2);
}

Datum int4shr(PG_FUNCTION_ARGS)
{
	int32		fc_arg1 = PG_GETARG_INT32(0);
	int32		fc_arg2 = PG_GETARG_INT32(1);

	PG_RETURN_INT32(fc_arg1 >> fc_arg2);
}

Datum int4not(PG_FUNCTION_ARGS)
{
	int32		fc_arg1 = PG_GETARG_INT32(0);

	PG_RETURN_INT32(~fc_arg1);
}

Datum int2and(PG_FUNCTION_ARGS)
{
	int16		fc_arg1 = PG_GETARG_INT16(0);
	int16		fc_arg2 = PG_GETARG_INT16(1);

	PG_RETURN_INT16(fc_arg1 & fc_arg2);
}

Datum int2or(PG_FUNCTION_ARGS)
{
	int16		fc_arg1 = PG_GETARG_INT16(0);
	int16		fc_arg2 = PG_GETARG_INT16(1);

	PG_RETURN_INT16(fc_arg1 | fc_arg2);
}

Datum int2xor(PG_FUNCTION_ARGS)
{
	int16		fc_arg1 = PG_GETARG_INT16(0);
	int16		fc_arg2 = PG_GETARG_INT16(1);

	PG_RETURN_INT16(fc_arg1 ^ fc_arg2);
}

Datum int2not(PG_FUNCTION_ARGS)
{
	int16		fc_arg1 = PG_GETARG_INT16(0);

	PG_RETURN_INT16(~fc_arg1);
}


Datum int2shl(PG_FUNCTION_ARGS)
{
	int16		fc_arg1 = PG_GETARG_INT16(0);
	int32		fc_arg2 = PG_GETARG_INT32(1);

	PG_RETURN_INT16(fc_arg1 << fc_arg2);
}

Datum int2shr(PG_FUNCTION_ARGS)
{
	int16		fc_arg1 = PG_GETARG_INT16(0);
	int32		fc_arg2 = PG_GETARG_INT32(1);

	PG_RETURN_INT16(fc_arg1 >> fc_arg2);
}

/*
 * 非持久数字序列生成器
 */
Datum generate_series_int4(PG_FUNCTION_ARGS)
{
	return generate_series_step_int4(fcinfo);
}

Datum generate_series_step_int4(PG_FUNCTION_ARGS)
{
	FuncCallContext *fc_funcctx;
	generate_series_fctx *fc_fctx;
	int32		fc_result;
	MemoryContext fc_oldcontext;

	/* 仅在函数的第一次调用时完成的工作 */
	if (SRF_IS_FIRSTCALL())
	{
		int32		fc_start = PG_GETARG_INT32(0);
		int32		fc_finish = PG_GETARG_INT32(1);
		int32		fc_step = 1;

		/* 检查我们是否被提供了显式步长 */
		if (PG_NARGS() == 3)
			fc_step = PG_GETARG_INT32(2);
		if (fc_step == 0)
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
					 errmsg("step size cannot equal zero")));

		/* 为跨调用持久性创建一个函数上下文 */
		fc_funcctx = SRF_FIRSTCALL_INIT();

		/*
		 * 切换到适合多次函数调用的内存上下文
		 */
		fc_oldcontext = MemoryContextSwitchTo(fc_funcctx->multi_call_memory_ctx);

		/* 为用户上下文分配内存 */
		fc_fctx = (generate_series_fctx *) palloc(sizeof(generate_series_fctx));

		/*
		 * 使用 fctx 在调用之间保持状态。用原始起始值初始化当前值
		 */
		fc_fctx->current = fc_start;
		fc_fctx->finish = fc_finish;
		fc_fctx->step = fc_step;

		fc_funcctx->user_fctx = fc_fctx;
		MemoryContextSwitchTo(fc_oldcontext);
	}

	/* 每次调用函数时完成的工作 */
	fc_funcctx = SRF_PERCALL_SETUP();

	/*
	 * 获取保存的状态，并将当前值作为本次迭代的结果
	 */
	fc_fctx = fc_funcctx->user_fctx;
	fc_result = fc_fctx->current;

	if ((fc_fctx->step > 0 && fc_fctx->current <= fc_fctx->finish) ||
		(fc_fctx->step < 0 && fc_fctx->current >= fc_fctx->finish))
	{
		/*
		 * 在为下一次迭代做准备时递增当前值。如果下一个值的
		 * 计算溢出，则这是最终结果。
		 */
		if (pg_add_s32_overflow(fc_fctx->current, fc_fctx->step, &fc_fctx->current))
			fc_fctx->step = 0;

		/* 当还有更多内容要发送时执行 */
		SRF_RETURN_NEXT(fc_funcctx, Int32GetDatum(fc_result));
	}
	else
		/* 当没有更多内容时执行 */
		SRF_RETURN_DONE(fc_funcctx);
}

/*
 * 生成序列(int4, int4 [, int4]) 的计划支持函数
 */
Datum generate_series_int4_support(PG_FUNCTION_ARGS)
{
	Node	   *fc_rawreq = (Node *) PG_GETARG_POINTER(0);
	Node	   *fc_ret = NULL;

	if (IsA(fc_rawreq, SupportRequestRows))
	{
		/* 尝试估算返回的行数 */
		SupportRequestRows *fc_req = (SupportRequestRows *) fc_rawreq;

		if (is_funcclause(fc_req->node))	/* 过于谨慎 */
		{
			List	   *fc_args = ((FuncExpr *) fc_req->node)->args;
			Node	   *fc_arg1,
					   *fc_arg2,
					   *fc_arg3;

			/* 在这里我们可以使用估计的参数值 */
			fc_arg1 = estimate_expression_value(fc_req->root, linitial(fc_args));
			fc_arg2 = estimate_expression_value(fc_req->root, lsecond(fc_args));
			if (list_length(fc_args) >= 3)
				fc_arg3 = estimate_expression_value(fc_req->root, lthird(fc_args));
			else
				fc_arg3 = NULL;

			/*
			 * 如果任何参数是常量 NULL，我们可以安全地假设返回零行。
			 * 否则，如果它们都是非 NULL 常量，我们可以计算将返回的行数。
			 * 使用双精度算术来避免溢出风险。
			 */
			if ((IsA(fc_arg1, Const) &&
				 ((Const *) fc_arg1)->constisnull) ||
				(IsA(fc_arg2, Const) &&
				 ((Const *) fc_arg2)->constisnull) ||
				(fc_arg3 != NULL && IsA(fc_arg3, Const) &&
				 ((Const *) fc_arg3)->constisnull))
			{
				fc_req->rows = 0;
				fc_ret = (Node *) fc_req;
			}
			else if (IsA(fc_arg1, Const) &&
					 IsA(fc_arg2, Const) &&
					 (fc_arg3 == NULL || IsA(fc_arg3, Const)))
			{
				double		fc_start,
							fc_finish,
							fc_step;

				fc_start = DatumGetInt32(((Const *) fc_arg1)->constvalue);
				fc_finish = DatumGetInt32(((Const *) fc_arg2)->constvalue);
				fc_step = fc_arg3 ? DatumGetInt32(((Const *) fc_arg3)->constvalue) : 1;

				/* 这个方程适用于步长的任意符号 */
				if (fc_step != 0)
				{
					fc_req->rows = floor((fc_finish - fc_start + fc_step) / fc_step);
					fc_ret = (Node *) fc_req;
				}
			}
		}
	}

	PG_RETURN_POINTER(fc_ret);
}
